#encoding:utf-8
'''
Created on 2015年7月1日

@author: LWD
'''

import re
import json
from bs4 import BeautifulSoup
import sys

from session import create_session
from src.store.CMySql import CMySql

reload(sys)
session = None

sqltmpl = "INSERT INTO user_info (user_id, user_name, followees, followers, agrees, thanks, asks, answers, collections, gender, introduction, company, location, business, position, description, education, major) \
                       VALUES ('%s', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')"

class User(object):
    '''
    @todo:  用户类：根据用户详细信息页（homepage/about）来获取用户个人信息
    包括用户名，一句话简介，个人介绍，教育经历，居住地，行业，职务，关注数，关注者数等
    '''
    user_url = None
    soup = None
    
    # 请求列表参数
    data = {
        '_xsrf': "",
        'method': "next",
        'params': ""
    }
    # post请求header, 火狐浏览器、Win7系统、
    header = {
        'User-Agent': "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:34.0) Gecko/20100101 Firefox/34.0",
        'Host': "www.zhihu.com",
        'Referer': ""
    }

    def __init__(self, user_url, user_id=None):
        '''
        @summary: 构造函数。
        @param user_url: 用户主页(homepage)
        @param user_id:  用户名(默认没有)
        '''
        # 回答等会出现匿名情况，故 如果没有user_url，认定用户名为"匿名用户"
        if user_url == None:
            self.user_id = "匿名用户".encode("utf-8")
        elif user_url[0:28] != "http://www.zhihu.com/people/":
            # 如果传递的url不是用户主页（homepage）格式，抛出异常
            raise ValueError("\"" + user_url + "\"" + " : it isn't a user url.")
        else:
            # 设置user_url为用户详情页
            self.user_url = user_url + "/about"
            # 如果传递了参数user_id， 则设置
            if user_id != None:
                self.user_id = user_id

    def parser(self):
        '''
        @summary: 获取指定网页的内容（content）,使用BeautifulSoup对页面解析 
        结果赋值给全局变量 session
        '''
        # 全局变量，web会话
        global session
        
        # 判断 如果当前会话不存在，创建一个会话，并登陆
        if session == None:
            session = create_session()
        s = session
        
        # 读取指定页面的内容（content）
        r = s.get(self.user_url)
        
        # 使用BeautifulSoup 解析
        soup = BeautifulSoup(r.content)
        self.soup = soup

    def store_into_db(self):
        '''
        @note: 此函数暂时不用，存储在类外，由数据库连接池实例对象实现
        @summary: 获取用户信息，并且插入到数据库中
        '''
        # 创建一个mysql操作类
        mysql = CMySql()
        # 读取mysql的配置文件
        mysql.read_options_config()
        # 创建一个mysql数据库连接
        mysql.create_connection()
        
        # 根据sql语句模板，组合sql语句
        sql = sqltmpl % (self._get_user_id(), self.get_user_id(), self.get_followees_num(), self.get_followers_num(), 
                         self.get_agree_num(), self.get_thanks_num(), self.get_asks_num(), 
                         self.get_answers_num(), self.get_collections_num(), self.get_gender(),
                         self.get_introduction(), self.get_company(), self.get_location(),
                         self.get_business(), self.get_position(), self.get_description(),
                         self.get_education(), self.get_major())
        
        print sql
        # 执行插入
        mysql.execute(sql)
        mysql.close_connection()
       
    def _get_user_id(self):
        '''
        @summary: 获取用户ID(user_id)，根据知乎主页网址格式，得到最后一个字段作为ID
        @return: user_id(字符串，全部由字母数字短线组成)
        '''
        if self.user_url == None:
            return '0'
        else:
            # 由于在构造函数中，url加上后缀"/about", 故去掉后六个字符
            return (self.user_url[28:])[:-6]
        
    def get_user_id(self):
        '''
        @summary: 解析页面，获取用户名 (user_name)，知乎页面显示的ID
        @return: user_id (字符串，编码：utf-8)
        '''
        # 如果没有用户主页，则用户名默认为“匿名用户”
        if self.user_url == None:
            return "匿名用户".encode("utf-8")
        else:
            # 如果已经设置了user_id，直接返回
            if hasattr(self, "user_id"):
                return self.user_id
            else:
                # 判断是否已经请求页面
                if self.soup == None:
                    # 如果没有，请求并解析页面
                    self.parser()
                soup = self.soup
                # 按照页面元素标签 及 css类 查找用户
                t_user_id = soup.find("div", class_="title-section ellipsis")
                if t_user_id == None:
                    return "匿名用户".encode("utf-8")
                user_id = t_user_id.find("a", class_="name").string.encode("utf-8")
                self.user_id = user_id
                return user_id

    def _get_element_from_content(self, label, lclass, flag = 0):
        '''
        @summary: 根据标签和css类名查找对应标签， 
        @param label: 要查找的HTML标签
        @param lclass: 要查找的标签的css类
        @param flag: 0：查找结果只有一个值； 非0： 查找结果是一个元组
        @return: 查找结果，如果flag是0，返回一条结果，否则，返回的是一个元组
        '''
        # 没有页面地址，直接返回None
        if self.user_url == None:
            print "I'm anonymous user."
            return None
        else:
            # 如果没有下载页面,则下载并解析页面
            if self.soup == None:
                self.parser()
            soup = self.soup
            # 根据flag 执行不同的查找方式
            if flag == 0:
                # 查找结果只有一个
                res = soup.find(label, class_=lclass)
            else:
                # 查找所有符合要求的标签
                res = soup.find_all(label, class_=lclass)
            
            if not res: # 结果是空
                return None
            return res
    
    def get_followees_num(self):
        '''
        @summary: 获取用户关注的人数，出错返回默认值 0
        @return: 关注的人数（int）
        '''
        res = self._get_element_from_content("div", "zm-profile-side-following zg-clear")
        if res == None:
            return 0
        followees_num = int(res.find("a").strong.string)
        return followees_num

    def get_followers_num(self):
        '''
        @summary: 获取关注用户的人数，出错返回默认值 0
        @return: 关注用户的人数（int）
        '''
        res = self._get_element_from_content("div", "zm-profile-side-following zg-clear")
        if res == None:
            return 0
        followers_num = int(res.find_all("a")[1].strong.string)
        return followers_num

    def get_agree_num(self):
        '''
        @summary: 获取用户获得的赞同数，出错返回默认值 0
        @return: 赞同数（int）
        '''
        res = self._get_element_from_content("span", "zm-profile-header-user-agree")
        if res == None:
            return 0
        agree_num = int(res.strong.string)
        return agree_num

    def get_thanks_num(self):
        '''
        @summary: 获取用户获得的感谢数，出错返回默认值 0
        @return: 感谢数（int）
        '''
        res = self._get_element_from_content("span", "zm-profile-header-user-thanks")
        if res == None:
            return 0
        thanks_num = int(res.strong.string)
        return thanks_num

    def get_asks_num(self):
        '''
        @summary: 获取用户提问数，出错返回默认值 0
        @return: 提问问题数（int）
        '''
        nums = self._get_element_from_content("span", "num", 1)
        if nums == None:
            return 0
        asks_num = int(nums[0].string)
        return asks_num

    def get_answers_num(self):
        '''
        @summary: 获取用户回答问题数，出错返回默认值 0
        @return: 回答问题数（int）
        '''
        nums = self._get_element_from_content("span", "num", 1)
        if nums == None:
            return 0
        answers_num = int(nums[1].string)
        return answers_num

    def get_collections_num(self):
        '''
        @summary: 获取用户收藏数，出错返回默认值 0
        @return: 收藏答案数（int）
        '''
        nums = self._get_element_from_content("span", "num", 1)
        if nums == None:
            return 0
        collections_num = int(nums[3].string)
        return collections_num

    def get_gender(self):
        '''
        @summary: 获取用户性别，1：男   2：女， 出错返回0  表示没有填写
        @return: 用户性别（int）
        '''
        res = self._get_element_from_content("span", "item gender")
        if res == None:
            return 0
        gender = res.i['class']
        # print gender
        if "icon-profile-male" in gender:
            gender = 1  # 男
        elif "icon-profile-female" in gender:
            gender = 2  # 女
        else:
            gender = 0 
        return gender
       
    def get_introduction(self):
        '''
        @summary: 获取用户一句话简介，如果出错，返回控制符串，表示用户没有填写
        @return: 用户的一句话介绍（字符串，编码：utf-8）
        '''
        res = self._get_element_from_content("div", "title-section ellipsis")
        if res == None:
            return ""
        introduction = res.find("span", class_="bio")
        # 如果没有填写
        if introduction == None:
            return ""
        return introduction.string.strip().encode("utf-8")

    def get_company(self):
        '''
        @summary: 获取用户所在公司，出错返回 空字符串，表示用户没有填写
        @return: 用户的公司名（字符串，编码：utf-8）
        '''
        company= self._get_element_from_content("span", "employment item")
        # 如果没有填写
        if company == None:
            return ""
        return company.string.encode("utf-8")

    def get_location(self):
        '''
        @summary: 获取用户居住地，出错返回空字符串，表示用户没有填写
        @return: 用户居住地（字符串，编码：utf-8）
        '''
        location = self._get_element_from_content("span", "location item")
        # lwd:2015-07-17  添加“or location.a == None”
        # 防止location下不存在 a 标签
        if location == None or location.a == None:
            return ""
        return location.a.string.encode("utf-8")
    
    def get_business(self):
        '''
        @summary: 获取用户所从事行业，出错返回空字符串，表示用户没有填写
        @return: 用户所在行业（字符串，编码：utf-8）
        '''
        business = self._get_element_from_content("span", "business item")
        if business == None or business.a == None:
            return ""
        return business.a.string.encode("utf-8")
    
    def get_position(self):
        '''
        @summary: 获取用户职务。出错返回 空字符串，表示用户没有填写
        @return: 用户职务（字符串，编码：utf-8）
        '''
        position = self._get_element_from_content("span", "position item")
        if position == None or position.a == None:
            return ""
        return position.a.string.encode("utf-8")
        
    def get_description(self):
        '''
        @summary: 获取用户自我介绍，出错返回空字符串，表示用户没有填写
        @return: 用户自我介绍（字符串，编码：utf-8）
        '''
        description = self._get_element_from_content("span", "content")
        if description == None:
            return ""
        return description.string.strip().encode("utf-8")
    
    def get_education(self):
        '''
        @summary: 获取用户教育经历（学校或教育机构名），只获取显示在详细信息区域的一条，出错返回空字符串，表示用户没有填写
        @return: 用户教育经历（字符串，编码：utf-8）
        '''
        education = self._get_element_from_content("span", "education item")
        if education == None or education.a == None:
            return ""
        return education.a.string.encode("utf-8")
               
    def get_major(self):
        '''
        @summary: 获取用户专业方向，出错返回空字符串，表示用户没有填写
        @return: 用户专业（字符串，编码：utf-8）
        '''
        major = self._get_element_from_content("span", "education-extra item")
        if major == None or major.a == None:
            return ""
        return major.a.string.encode("utf-8")
        
    def get_rfollowees(self):
        '''
        @summary: 获取经过筛选之后，用户的关注数
        @return: 筛选后的用户关注数(int)
        '''
        if hasattr(self, "rfollowees"):
            return self.rfollowees
        return 0
    
    def get_jumped_followees_list(self):
        '''
        @summary: 获取筛选掉的当前用户关注的用户列表
        @return: 如果有，则返回筛序掉用户列表，如果没有，返回 None
        '''
        if hasattr(self, "jumped_followees_list"):
            return self.jumped_followees_list
        return None
        
    def get_followees(self):
        global session
        global cookies
        
        self.rfollowees = 0
        self.jumped_followees_list = []

        if self.user_url == None:
            print "I'm anonymous user."
            return
            yield
        else:
            followees_num = self.get_followees_num()
            if followees_num == 0:
                return
                yield
            else:
                if session == None:
                    session = create_session()
                s = session
                
                followee_url = self.user_url[:-6] + "/followees"
                r = s.get(followee_url)
                soup = BeautifulSoup(r.content)
                
                for i in xrange((followees_num - 1) / 20 + 1):
                    if i == 0:
                        user_list_content = soup.find_all("div", class_="zm-list-content-medium")
                        for j in xrange(min(followees_num, 20)):
                            user_id = user_list_content[j].h2.a["href"][28:]
                            attrs = user_list_content[j].find_all("a", class_="zg-link-gray-normal")
                            # 关注者数
                            f_num = int(attrs[0].string[:-3])
                            # 问题数
                            a_num = int(attrs[1].string[:-2])
                            # 回答数
                            an_num = int(attrs[2].string[:-2])
                            # 赞同数
                            ag_num = int(attrs[3].string[:-2])
                            if (f_num + a_num + an_num + ag_num) < 10:
                                self.jumped_followees_list.append(user_id)
                                continue
                            self.rfollowees += 1
                            yield user_id
#                             t_followees_list.append(user_id) 
                    else:
                        post_url = "http://www.zhihu.com/node/ProfileFolloweesListV2"
                        _xsrf = soup.find("input", attrs={'name': '_xsrf'})["value"]
                        offset = i * 20
                        hash_id = re.findall("hash_id&quot;: &quot;(.*)&quot;},", r.text)[0]
                        params = json.dumps({"offset": offset, "order_by": "created", "hash_id": hash_id})
                        self.data['_xsrf'] = _xsrf,
                        self.data['params'] = params
                        self.header['Referer'] = followee_url
                        
                        r_post = s.post(post_url, data=self.data, headers=self.header)
                        followee_list = r_post.json()["msg"]
                        for j in xrange(min(followees_num - i * 20, 20)):
                            follower_soup = BeautifulSoup(followee_list[j])
                            user_link = follower_soup.find("h2", class_="zm-list-content-title").a
                            user_id = user_link["href"][28:]
                            attrs = follower_soup.find_all("a", class_="zg-link-gray-normal")
                            # 关注者数
                            f_num = int(attrs[0].string[:-3])
                            # 问题数
                            a_num = int(attrs[1].string[:-2])
                            # 回答数
                            an_num = int(attrs[2].string[:-2])
                            # 赞同数
                            ag_num = int(attrs[3].string[:-2])
                            if (f_num + a_num + an_num + ag_num) < 10:
                                self.jumped_followees_list.append(user_id)
                                continue
                            self.rfollowees += 1
                            yield user_id

    
    def get_rfollowers(self):
        '''
        @summary: 获取经过筛选之后，用户的关注者数
        @return: 筛选后的用户关注者数(int)
        '''
        if hasattr(self, "rfollowers"):
            return self.rfollowers
        return 0

    def get_jumped_followers_list(self):
        '''
        @summary: 获取筛选掉的关注当前用户的用户列表
        @return: 如果有，则返回筛序掉用户列表，如果没有，返回 None
        '''
        if hasattr(self, "jumped_followers_list"):
            return self.jumped_followers_list
        return None

    def get_followers(self):
        '''
        @summary: 获取当前用户的所有关注者，并且选中其中关注数 + 提问数 + 回答数 + 赞同数 超过10
        的用户返回，将跳过的用户存储到 jumped_followers_list中。注意：使用了yield关键字，读取时，需要循环
        '''
        global session
        global cookies
        
        self.rfollowers = 0
        self.jumped_followers_list = []
        
        if self.user_url == None:
            print "I'm anonymous user."
            return
            yield
        else:
            followers_num = self.get_followers_num()
            if followers_num == 0:
                return
                yield
            else:
                if session == None:
                    create_session()
                s = session
                follower_url = self.user_url[:-6] + "/followers"
                
                r = s.get(follower_url)
                soup = BeautifulSoup(r.content)
                for i in xrange((followers_num - 1) / 20 + 1):
#                     t_followers_list = []
                    if i == 0:
                        user_list_content = soup.find_all("div", class_="zm-list-content-medium")
                        for j in xrange(min(followers_num, 20)):
                            user_id = user_list_content[j].h2.a["href"][28:]
                            attrs = user_list_content[j].find_all("a", class_="zg-link-gray-normal")
                            # 关注者数
                            f_num = int(attrs[0].string[:-3])
                            # 问题数
                            a_num = int(attrs[1].string[:-2])
                            # 回答数
                            an_num = int(attrs[2].string[:-2])
                            # 赞同数
                            ag_num = int(attrs[3].string[:-2])
                            if (f_num + a_num + an_num + ag_num) < 10:
                                self.jumped_followers_list.append(user_id)
                                continue
                            self.rfollowers += 1
                            yield user_id
#                             t_followers_list.append(user_id)
#                             self.rfollowers += 1                            
                    else:
                        post_url = "http://www.zhihu.com/node/ProfileFollowersListV2"
                        _xsrf = soup.find("input", attrs={'name': '_xsrf'})["value"]
                        offset = i * 20
                        hash_id = re.findall("hash_id&quot;: &quot;(.*)&quot;},", r.text)[0]
                        params = json.dumps({"offset": offset, "order_by": "created", "hash_id": hash_id})
                        self.data['_xsrf'] = _xsrf,
                        self.data['params'] = params
                        self.header['Referer'] = follower_url
                        
                        r_post = s.post(post_url, data=self.data, headers=self.header)
                        follower_list = r_post.json()["msg"]
                        for j in xrange(min(followers_num - i * 20, 20)):
                            follower_soup = BeautifulSoup(follower_list[j])
                            user_link = follower_soup.find("h2", class_="zm-list-content-title").a
                            user_id = user_link["href"][28:]
                            attrs = follower_soup.find_all("a", class_="zg-link-gray-normal")
                            # 关注者数
                            f_num = int(attrs[0].string[:-3])
                            # 问题数
                            a_num = int(attrs[1].string[:-2])
                            # 回答数
                            an_num = int(attrs[2].string[:-2])
                            # 赞同数
                            ag_num = int(attrs[3].string[:-2])
                            if (f_num + a_num + an_num + ag_num) < 10:
                                self.jumped_followers_list.append(user_id)
                                continue
                            self.rfollowers += 1
                            yield user_id
#                             t_followers_list.append(user_id)                        
#                         yield t_followers_list

    def get_asks(self):
        '''
        @todo: 获取用户所有提问
        '''
        pass

    def get_answers(self):
        '''
        @todo: 获取用户的所有回答
        '''
        pass

    def get_collections(self):
        '''
        @todo: 获取用户的所有收藏
        '''
        pass
